.iCall <- function(...) .Call(...)

setClass("Geometry", representation (
  pointer = "externalptr"), 
  prototype = list(pointer=NULL)
)

setClass("GeoPoint", contains = "Geometry")

setClass("GeoLine", contains = "Geometry")

setClass("GeoRegion", contains = "Geometry")

valid.classes <-  c('Geometry', 'GeoPoint', 'GeoLine', 'GeoRegion')

geometry.create <- function(geoType){
  str.type <-  c(1L, 3L, 5L)
  if(is.integer(geoType) && length(str.type[(str.type == geoType)]) == 1){
    .iCall('R_Geometry_create', geoType, PACKAGE='RSuperMap')
  }
  else{
    stop("Error geometry type. The valid geometry type is integer (1L, 3L, 5L)")
  }
}

geometry.type <- function(obj){
  if(!is.null(obj) && length(valid.classes[(valid.classes == class(obj))]) == 1){
    return(.iCall('R_Geometry_getType', obj@pointer, PACKAGE='RSuperMap'))
  }
  else{
    stop("invalid object. must be (Geometry, GeoPoint, GeoLine, GeoRegion)")
  }
}

geometry.inner.point <- function(obj){
  if(!is.null(obj) && length(valid.classes[(valid.classes == class(obj))]) == 1){
    xy <- .iCall("R_Geometry_getInnerPoint", obj@pointer, PACKAGE="RSuperMap")
    if(!is.null(xy) && is.vector(xy) && length(xy) >= 2){
      return(matrix(data=xy, nrow=1, ncol=2))
    }
    else{
      stop("computing inner point failure ")
    }
  }
  else{
    stop("invalid object. must be (Geometry, GeoPoint, GeoLine, GeoRegion)")
  }
}

geometry.create.point <- function(x, y){
  geo = geometry.create(1L)
  if(!is.null(geo)){
    if(geometry.make(geo, x, y)){
      return(geo)
    }
    else{
      stop("setting point to geometry failure")
    }
  } 
  else{
    stop("creating geometry failure")
  }
}

geometry.create.line <- function(xys, polys){
  if(is.null(xys) || !is.matrix(xys)){
    stop("xys is not a matrix")
  }
  if(ncol(xys) < 2){
    stop("xys's col number must be greater 2")
  }
  if(is.null(polys) || !is.vector(polys)){
    stop("polys is not a vector")
  }
  if(sum(polys) != length(xys[,1])){
    stop("polys sum is not equal points size")
  }
  geo = geometry.create(3L)
  if(!is.null(geo)){
    if(geometry.make(geo, xys[,1],xys[,2], polys)){
      return(geo)
    }
    else{
      stop("setting points to geometry failure")
    }
  }
  else{
    stop("creating geometry failure")
  }
}

geometry.create.region <- function(xys, polys){
  if(is.null(xys) || !is.matrix(xys)){
    stop("xys is not a matrix")
  }
  if(ncol(xys) < 2){
    stop("xys's col number must be greater 2")
  }
  if(is.null(polys) || !is.vector(polys)){
    stop("polys is not a vector")
  }
  if(sum(polys) != length(xys[,1])){
    stop("polys sum is not equal points size")
  }
  geo = geometry.create(5L)
  if(!is.null(geo)){
    if(geometry.make(geo, xys[,1],xys[,2], polys)){
      return(geo)
    }
    else{
      stop("setting points to geometry failure")
    }
  }
  else{
    stop("creating geometry failure")
  }
}

setGeneric("geometry.make", function(obj, ...){
  standardGeneric( "geometry.make" )
})

setMethod("geometry.make", "Geometry", function(obj, xs, ys, polys){
  .iCall("R_Geometry_make", obj@pointer, x, y, PACKAGE="RSuperMap")
})

setMethod("geometry.make", "GeoPoint", function(obj, x, y){
  .iCall("R_GeoPoint_make", obj@pointer, x, y, PACKAGE="RSuperMap")
})

setMethod("geometry.make", "GeoLine", function(obj, xs, ys, polys){
  .iCall("R_Geometry_make", obj@pointer, xs, ys, polys, PACKAGE="RSuperMap")
})

setMethod("geometry.make", "GeoRegion", function(obj, xs, ys, polys){
  .iCall("R_Geometry_make", obj@pointer, xs, ys, polys, PACKAGE="RSuperMap")
})

setGeneric("geometry.length", function(obj){
  standardGeneric( "geometry.length" )
})

setMethod("geometry.length", "GeoLine", function(obj){
  .iCall("R_Geometry_getLength", obj@pointer, PACKAGE="RSuperMap")
})

setMethod("geometry.length", "GeoRegion", function(obj){
  .iCall("R_Geometry_getLength", obj@pointer, PACKAGE="RSuperMap")
})

setGeneric("geometry.id.get", function(obj){
  standardGeneric( "geometry.id.get" )
})


setMethod("geometry.id.get", "Geometry", function(obj){
  .iCall("R_Geometry_getID", obj@pointer, PACKAGE="RSuperMap")
})

setMethod("geometry.id.get", "GeoPoint", function(obj){
  .iCall("R_Geometry_getID", obj@pointer, PACKAGE="RSuperMap")
})

setMethod("geometry.id.get", "GeoLine", function(obj){
  .iCall("R_Geometry_getID", obj@pointer, PACKAGE="RSuperMap")
})

setMethod("geometry.id.get", "GeoRegion", function(obj){
  .iCall("R_Geometry_getID", obj@pointer, PACKAGE="RSuperMap")
})

setGeneric("geometry.id.set", function(obj,...){
  standardGeneric( "geometry.id.set" )
})

setMethod("geometry.id.set", "Geometry", function(obj,id){
  .iCall("R_Geometry_setID", obj@pointer,id, PACKAGE="RSuperMap")
})

setMethod("geometry.id.set", "GeoPoint", function(obj,id){
  .iCall("R_Geometry_setID", obj@pointer,id, PACKAGE="RSuperMap")
})

setMethod("geometry.id.set", "GeoLine", function(obj,id){
  .iCall("R_Geometry_setID", obj@pointer,id, PACKAGE="RSuperMap")
})

setMethod("geometry.id.set", "GeoRegion", function(obj,id){
  .iCall("R_Geometry_setID", obj@pointer,id, PACKAGE="RSuperMap")
})

setGeneric("geometry.spatial.points", function(obj){
  standardGeneric( "geometry.spatial.points" )
})

setMethod("geometry.spatial.points", "Geometry", function(obj){
  points <- .iCall("R_Geometry_getPoints", obj@pointer, PACKAGE="RSuperMap")
  
  if(!is.null(points) && length(points) == 3){
    xs <- points[1]
    ys <- points[2]
    polyCounts <- points[3]
    pnts = matrix(nrow=length(xs[[1]]), ncol=2))
    pnts[,1] = xs[[1]]
    pnts[,2] = ys[[1]]
    return( list(pnts, polyCounts[[1]]) )
  }
  else{
    warning("getting points failure")
  }
})

setMethod("geometry.spatial.points", "GeoPoint", function(obj){
  geometry.inner.point(obj)
})

setMethod("geometry.spatial.points", "GeoLine", function(obj){
  points <- .iCall("R_Geometry_getPoints", obj@pointer, PACKAGE="RSuperMap")
  if(!is.null(points) && length(points) == 3){
    xs <- points[1]
    ys <- points[2]
    polyCounts <- points[3]
    pnts = matrix(nrow=length(xs[[1]]), ncol=2))
    pnts[,1] = xs[[1]]
    pnts[,2] = ys[[1]]
    return( list(pnts, polyCounts[[1]]) )
  }
  else{
    warning("getting points failure")
  }
})

setMethod("geometry.spatial.points", "GeoRegion", function(obj){
  points <- .iCall("R_Geometry_getPoints", obj@pointer, PACKAGE="RSuperMap")
  if(!is.null(points) && length(points) == 3){
    xs <- points[1]
    ys <- points[2]
    polyCounts <- points[3]
    pnts = matrix(nrow=length(xs[[1]]), ncol=2))
    pnts[,1] = xs[[1]]
    pnts[,2] = ys[[1]]
    return( list(pnts, polyCounts[[1]]) )
  }
  else{
    warning("getting points failure")
  }
})

setGeneric("geometry.dimension", function(obj){
  standardGeneric( "geometry.dimension" )
})

setMethod("geometry.dimension", "Geometry", function(obj){
  .iCall("R_Geometry_getDimension", obj@pointer, PACKAGE="RSuperMap")
})

setMethod("geometry.dimension", "GeoPoint", function(obj){
  .iCall("R_Geometry_getDimension", obj@pointer, PACKAGE="RSuperMap")
})

setMethod("geometry.dimension", "GeoLine", function(obj){
  .iCall("R_Geometry_getDimension", obj@pointer, PACKAGE="RSuperMap")
})

setMethod("geometry.dimension", "GeoRegion", function(obj){
  .iCall("R_Geometry_getDimension", obj@pointer, PACKAGE="RSuperMap")
})

setGeneric("geometry.area", function(obj){
  standardGeneric( "geometry.area" )
})

setMethod("geometry.area", "Geometry", function(obj){
  .iCall("R_Geometry_getArea", obj@pointer, PACKAGE="RSuperMap")
})

setMethod("geometry.area", "GeoRegion", function(obj){
  .iCall("R_Geometry_getArea", obj@pointer, PACKAGE="RSuperMap")
})


setGeneric("geometry.bounds", function(obj){
  standardGeneric( "geometry.bounds" )
})

setMethod("geometry.bounds", "Geometry", function(obj){
  bounds <- .iCall("R_Geometry_getBounds", obj@pointer, PACKAGE="RSuperMap")
  if(!is.null(bounds) && length(bounds) >= 4){
    bbox = matrix(nrow=2,ncol=2)
    bbox[,1]=c(bounds[1],bounds[3])
    bbox[,2]=c(bounds[2],bounds[4])
    return(bbox)
  }
  else{
    stop("computing geometry bounds failure")
  }
})

setMethod("geometry.bounds", "GeoPoint", function(obj){
  bounds <- .iCall("R_Geometry_getBounds", obj@pointer, PACKAGE="RSuperMap")
  if(!is.null(bounds) && length(bounds) >= 4){
    bbox = matrix(nrow=2,ncol=2)
    bbox[,1]=c(bounds[1],bounds[3])
    bbox[,2]=c(bounds[2],bounds[4])
    return(bbox)
  }
  else{
    stop("computing geometry bounds failure")
  }
})

setMethod("geometry.bounds", "GeoLine", function(obj){
  bounds <- .iCall("R_Geometry_getBounds", obj@pointer, PACKAGE="RSuperMap")
  if(!is.null(bounds) && length(bounds) >= 4){
    bbox = matrix(nrow=2,ncol=2)
    bbox[,1]=c(bounds[1],bounds[3])
    bbox[,2]=c(bounds[2],bounds[4])
    return(bbox)
  }
  else{
    stop("computing geometry bounds failure")
  }
})

setMethod("geometry.bounds", "GeoRegion", function(obj){
  bounds <- .iCall("R_Geometry_getBounds", obj@pointer, PACKAGE="RSuperMap")
  if(!is.null(bounds) && length(bounds) >= 4){
    bbox = matrix(nrow=2,ncol=2)
    bbox[,1]=c(bounds[1],bounds[3])
    bbox[,2]=c(bounds[2],bounds[4])
    return(bbox)
  }
  else{
    stop("computing geometry bounds failure")
  }
})

